/*
 * Copyright  2017-2019 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_common.h"
#include "fsl_elcdif.h"
#include "fsl_debug_console.h"

#include "fsl_gpio.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "softspi.h"
extern void InitTouch(void);
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define APP_ELCDIF LCDIF

#define APP_IMG_HEIGHT 800
#define APP_IMG_WIDTH  480
#define APP_HSW        20
#define APP_HFP        112
#define APP_HBP        100
#define APP_VSW        6
#define APP_VFP        20
#define APP_VBP        14
#define APP_POL_FLAGS \
    (kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnRisingClkEdge)

/* Display. */
#define LCD_DISP_GPIO     GPIO1
#define LCD_DISP_GPIO_PIN 2
/* Back light. */
#define LCD_BL_GPIO     GPIO2
#define LCD_BL_GPIO_PIN 31

/* Frame buffer data alignment, for better performance, the LCDIF frame buffer should be 64B align. */
#define FRAME_BUFFER_ALIGN 64

//#ifndef APP_LCDIF_DATA_BUS
//#define APP_LCDIF_DATA_BUS kELCDIF_DataBus24Bit
//#endif

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void BOARD_EnableLcdInterrupt(void);

extern int hyper_ram_init(void);
/*******************************************************************************
 * Variables
 ******************************************************************************/
static volatile bool s_frameDone = false;
#if use_hyperram == 1
#define FRAME_BUFFER_FRONT_ADDRESS 0x60000000
#define FRAME_BUFFER_BACK_ADDRESS 0x600bb800
#else
#define FRAME_BUFFER_FRONT_ADDRESS 0x80000000
#define FRAME_BUFFER_BACK_ADDRESS 0x800bb800
#endif
uint16_t* s_frameBuffer_front = (uint16_t*)FRAME_BUFFER_FRONT_ADDRESS;
uint16_t* s_frameBuffer_back = (uint16_t*)FRAME_BUFFER_BACK_ADDRESS;

/*******************************************************************************
 * Code
 ******************************************************************************/
extern void APP_LCDIF_IRQHandler(void);
extern int gui_app_start(int lcd_w, int lcd_h);

void LCDIF_IRQHandler(void)
{
    APP_LCDIF_IRQHandler();
}

/* Enable interrupt. */
void BOARD_EnableLcdInterrupt(void)
{
    EnableIRQ(LCDIF_IRQn);
}

/* Initialize the LCD_DISP. */
void BOARD_InitLcd(void)
{
    volatile uint32_t i = 0x1000U;

    gpio_pin_config_t config = {
        kGPIO_DigitalOutput,
        0,
        kGPIO_NoIntmode,
    };

    GPIO_PinWrite(LCD_DISP_GPIO, LCD_DISP_GPIO_PIN, 1);

    /* Backlight. */
    config.outputLogic = 1;
    GPIO_PinInit(LCD_BL_GPIO, LCD_BL_GPIO_PIN, &config);
}

void BOARD_InitLcdifPixelClock(void)
{
    /*
     * The desired output frame rate is 60Hz. So the pixel clock frequency is:
     * (480 + 41 + 4 + 18) * (272 + 10 + 4 + 2) * 60 = 9.2M.
     * Here set the LCDIF pixel clock to 9.3M.
     */

    /*
     * Initialize the Video PLL.
     * Video PLL output clock is OSC24M * (loopDivider + (denominator / numerator)) / postDivider = 93MHz.
     */
    clock_video_pll_config_t config = {
        .loopDivider = 31,
        .postDivider = 8,
        .numerator   = 0,
        .denominator = 0,
    };

    CLOCK_InitVideoPll(&config);

    /*
     * 000 derive clock from PLL2
     * 001 derive clock from PLL3 PFD3
     * 010 derive clock from PLL5
     * 011 derive clock from PLL2 PFD0
     * 100 derive clock from PLL2 PFD1
     * 101 derive clock from PLL3 PFD1
     */
    CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);

    CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 4);

    CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
}


void APP_LCDIF_IRQHandler(void)
{
    uint32_t intStatus;

    intStatus = ELCDIF_GetInterruptStatus(APP_ELCDIF);

    ELCDIF_ClearInterruptStatus(APP_ELCDIF, intStatus);

    if (intStatus & kELCDIF_CurFrameDone)
    {
        s_frameDone = true;
    }
    SDK_ISR_EXIT_BARRIER;
}

void APP_ELCDIF_Init(void)
{
    const elcdif_rgb_mode_config_t config = {
        .panelWidth    = APP_IMG_WIDTH,
        .panelHeight   = APP_IMG_HEIGHT,
        .hsw           = APP_HSW,
        .hfp           = APP_HFP,
        .hbp           = APP_HBP,
        .vsw           = APP_VSW,
        .vfp           = APP_VFP,
        .vbp           = APP_VBP,
        .polarityFlags = APP_POL_FLAGS,
        .bufferAddr    = (uint32_t)s_frameBuffer_front,
        .pixelFormat   = kELCDIF_PixelFormatRGB565,
        .dataBus       = APP_LCDIF_DATA_BUS,
    };

#if (defined(APP_ELCDIF_HAS_DISPLAY_INTERFACE) && APP_ELCDIF_HAS_DISPLAY_INTERFACE)
    BOARD_InitDisplayInterface();
#endif
    ELCDIF_RgbModeInit(APP_ELCDIF, &config);
}

void SetDisplayMemory(uint16_t* displayMemory,uint32_t size,uint16_t color)
{
	for(uint32_t i = 0;i<size;i++)
	{
		displayMemory[i] = color;
	}
}

/*!
 * @brief Main function
 */
int main(void)
{
    uint32_t frameBufferIndex = 0;

    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitSemcPins();
    BOARD_InitBootClocks();
    BOARD_InitLcdifPixelClock();
    BOARD_InitDebugConsole();
    BOARD_InitLcd();
    
    SysTick_Config(SystemCoreClock / (1 * 1000U));

    PRINTF("LCDIF RGB example start...\r\n");
    hyper_ram_init();
    APP_ELCDIF_Init();

    MySPI_Init();
    
    LCD_Init();
    InitTouch();
    BOARD_EnableLcdInterrupt();

    
    
    /* Clear the frame buffer. */
    
    
    
    //APP_FillFrameBuffer(s_frameBuffer[frameBufferIndex]);

    ELCDIF_EnableInterrupts(APP_ELCDIF, kELCDIF_CurFrameDoneInterruptEnable);
    ELCDIF_RgbModeStart(APP_ELCDIF);
    
    
    return gui_app_start(480,800);
    
    while (1)
    {
        frameBufferIndex ^= 1U;

        if(frameBufferIndex)
        {
            SetDisplayMemory((uint16_t*)s_frameBuffer_front,480*800,0x01f0);
            SDK_DelayAtLeastUs(1000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);    
            ELCDIF_SetNextBufferAddr(APP_ELCDIF,(uint32_t)s_frameBuffer_front);
        }else{
            SetDisplayMemory((uint16_t*)s_frameBuffer_back,480*800,0xf800);
            SDK_DelayAtLeastUs(1000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);    
            ELCDIF_SetNextBufferAddr(APP_ELCDIF,(uint32_t)s_frameBuffer_back);
        }
        

        s_frameDone = false;
        /* Wait for previous frame complete. */
        while (!s_frameDone)
        {
        }
    }
}
